////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Project Name: ARS Logs Reader
// Version: 1.0
// File Name: 'logfilewidget.cpp'
// Purpose: 'LogFileWidget', 'LogTableModel' classes implementation
//
////////////////////////////////////////////////////////////////////////////////////////////////////

///////// Include Files ////////////////////////////////////////////////////////////////////////////

#include <QMessageBox>
#include <QMouseEvent>
#include <QBoxLayout>
#include <QTextStream>
#include <QGraphicsTextItem>
#include <QGraphicsRectItem>
#include <QRadialGradient>
#include <QLinearGradient>
#include <QLabel>
#include <QAction>
#include <QSplitter>
#include <QActionGroup>
#include <QMetaProperty>
#include <QTextEdit>
#include <QPushButton>
#include <QMessageBox>
#include <QScrollBar>
#include <QGraphicsOpacityEffect>
#include <QApplication>
#include <QClipboard>
#include <QGraphicsEffect>
#include <QPropertyAnimation>
#include <QLineEdit>

#include <QHeaderView>
#include <math.h>
//#include <iostream>

#include "treeview.h"
//#include "objectsindex.h"
//#include "settings.h"

///////// Class 'DebugTreeFieldIndex' declaration //////////////////////////////////////////////////

DebugTreeFieldIndex::DebugTreeFieldIndex()
{
}

DebugTreeFieldIndex::DebugTreeFieldIndex( QModelIndex itemIndex, QString propertyName )
{
    m_itemIndex = itemIndex;
    m_propertyName = propertyName;
}

bool DebugTreeFieldIndex::isValid() const
{
    return m_itemIndex.isValid();
}

QModelIndex DebugTreeFieldIndex::itemIndex() const
{
    return m_itemIndex;
}

QString DebugTreeFieldIndex::propertyName() const
{
    return m_propertyName;
}

///////// Class 'DebugTreeView' implementation /////////////////////////////////////////////////////

TreeView::TreeView( QWidget * parent )
             : QTreeView(parent)
{
    QFile styleFile("qss/mainview.qss");
    styleFile.open(QIODevice::ReadOnly);
    m_repaint_counter = 100;

    m_searchActive = false;
    m_shadowAnimationProcess = 0;
    m_model = 0;
    m_currentFilterMode = TreeViewFilterProxyModel::ShowAllWorkflow;

    setStyleSheet(styleFile.readAll());
    setAnimated(false);
    setAutoExpandDelay(10);
    setVerticalScrollMode(ScrollPerPixel);
    setIndentation(20);
    setMouseTracking(true);
    setHeaderHidden(true);
    header()->setOffset(-(MarginWidth + indentation() / 2));

    TreeViewDelegate * itemDelegate = new TreeViewDelegate(this);
    setItemDelegate(itemDelegate);

    m_commentEditDialog = new CommentEditDialog(parentWidget());
//    setUniformRowHeights(true);
}

//ARSExecAction::ActionType TreeView::actionsFilter() const
//{
//    return m_actionsFilter;
//}

//void TreeView::setActionsFilter( ARSExecAction::ActionType filter )
//{
//    m_actionsFilter = filter;
//    m_filterModel->setActionsFilter(filter);
//    setModel(m_filterModel);
//    expandAll();
//}

//bool TreeView::showEmptyWorkflow() const
//{
//    return m_showEmptyWorkflow;
//}

//bool TreeView::docViewActive()
//{
//    return m_docViewActive;
//}

//void TreeView::setDocViewActive( bool active )
//{
//    m_docViewActive = active;
//    m_filterModel->setDocViewActive(active);
//}

void TreeView::copy()
{
    if(!m_selectedField.isValid())
        return;

    QString selectedText = TreeViewDelegate::field2String(TreeViewModel::item(m_selectedField.itemIndex()),
                                                          m_selectedField.propertyName());
    QClipboard * clipboard = QApplication::clipboard();
    clipboard->setText(selectedText);
}

void TreeView::mouseMoveEvent( QMouseEvent * event )
{
    checkHoveredItems();
}

void TreeView::mousePressEvent( QMouseEvent * event )
{
    QPoint mousePos = event->pos();

    if(mousePos.x() < MarginWidth)
    {
        QModelIndex myIndex = indexAt(mousePos + QPoint(MarginWidth + indentation() / 2 + 10, 0));
        QModelIndex index = m_filterModels[m_currentFilterMode]->mapToSource(myIndex);
        if(m_bookmarksList.contains(index))
        {
            m_bookmarksList.removeOne(index);
            emit bookmarkRemoved(index);
        }
        else
        {
            m_bookmarksList.append(index);
            emit bookmarkAdded(index);
            animateItem(index);
        }

        repaint(0, 0, MarginWidth, height());
    }

    if(m_hoveredBranch.isValid())
        scrollTo(m_hoveredBranch);

    if(m_hoveredField.isValid())
    {
        if(event->button() == Qt::LeftButton)
        {
            m_selectedField = m_hoveredField;
        }
    }
    else
    {
        m_selectedField = DebugTreeFieldIndex();
    }

    QTreeView::mousePressEvent(event);
}

void TreeView::mouseDoubleClickEvent( QMouseEvent *event )
{
    if(!m_hoveredField.isValid())
        return;

    QModelIndex commentIndex = m_hoveredField.itemIndex();
    ARSExecItem * item = TreeViewModel::item(commentIndex);
    m_commentEditDialog->setText(item->comment());
    if(m_commentEditDialog->exec() == QDialog::Accepted)
    {
        item->setComment(m_commentEditDialog->text());
        dataChanged(commentIndex, commentIndex);
        animateItem(commentIndex);
    }
}

void TreeView::leaveEvent( QEvent * event )
{
    if(m_hoveredBranch.isValid())
    {
        int hoveredBranchX = visualRect(m_hoveredBranch).left();
        m_hoveredBranch = QModelIndex();
        repaint(hoveredBranchX, 0, indentation(), rect().height());
        repaint(0, 0, rect().width(), BranchTooltipHeight + 2);
    }

    if(m_hoveredField.isValid())
    {
        QRect hoveredItemRect = visualRect(m_hoveredField.itemIndex());
        m_hoveredField = DebugTreeFieldIndex();
        repaint(hoveredItemRect);
    }
}

void TreeView::scrollContentsBy( int dx, int dy )
{
    QTreeView::scrollContentsBy(dx, dy);

    generateScreenPos();
    checkHoveredItems();
}

void TreeView::resizeEvent( QResizeEvent * event )
{
    QTreeView::resizeEvent(event);
    generateScreenPos();
}

void TreeView::drawBranchess( QPainter * painter, const QRect & rect, const QModelIndex & index ) const
{
    ARSExecItem * currentItem = TreeViewModel::item(index);
    ARSExecItem * item = currentItem->parent();
    const TextStyle * style;
    int level = 1;
    int branchX;
    bool drawBranch;
    QColor highlightColor(160, 200, 50);
    QColor branchColor(160, 180, 255);
    QColor noBranchColor(220, 220, 230);

    if(item->type() == ARSExecItem::ItemTypeRoot)
        return;

    painter->save();

    painter->fillRect(rect, Qt::white);
    painter->setPen(QPen(QColor(200, 200, 200), 1, Qt::SolidLine));

    while(item->parent())
    {
        drawBranch = true;
        branchX = rect.right() - indentation() * level - indentation() / 2;

        if(m_hoveredBranch.isValid() && m_model->index(item).parent() == m_hoveredBranch)
            painter->setPen(highlightColor);
        else
            if(item->isLastChild())
            {
                if(visualRect(m_model->index(item)).bottom() < 0)
                    painter->setPen(noBranchColor);
                else
                    drawBranch = false;
            }
            else
                painter->setPen(branchColor);

        if(drawBranch)
            painter->drawLine(branchX, rect.top(), branchX, rect.bottom());

        item = item->parent();
        level++;
    }

    if(currentItem->hasChildren())
    {
        if(m_hoveredBranch.isValid() && m_model->index(currentItem->parent()) == m_hoveredBranch)
            painter->setPen(highlightColor);
        else
            painter->setPen(branchColor);

        if(currentItem->row() != 0)
            painter->drawLine(rect.right() - indentation() / 2, rect.top(),
                              rect.right() - indentation() / 2, rect.center().y());

        if(!currentItem->isLastChild())
            painter->drawLine(rect.right() - indentation() / 2, rect.center().y(),
                              rect.right() - indentation() / 2, rect.bottom());

        painter->fillRect(rect.right() - 15, rect.center().y() - 4, 10, 10, Qt::white);
        painter->drawRoundedRect(QRect(rect.right() - 15, rect.center().y() - 4, 10, 10), 2, 2);

        painter->drawLine(rect.right() - 13, rect.center().y() + 1, rect.right() - 7, rect.center().y() + 1);

        if(!isExpanded(index))
            painter->drawLine(rect.right() - indentation() / 2, rect.center().y() - 2,
                              rect.right() - indentation() / 2, rect.center().y() + 4);
    }
    else
    {
        painter->setPen(branchColor);
        branchX = rect.right() - indentation() / 2;
        painter->drawLine(branchX, rect.top(), branchX, rect.bottom());
    }

    painter->restore();
}

void TreeView::paintEvent( QPaintEvent * event )
{
    QTreeView::paintEvent(event);

    QPainter painter(viewport());

    painter.fillRect(0, 0, MarginWidth, height(), Qt::white);
    QRect bookmarksRect(0, 0, MarginWidth, height());
    painter.setPen(QPen(QColor::fromHsv(0, 0, 200), 1));
    painter.drawLine(bookmarksRect.topRight(), bookmarksRect.bottomRight());

    foreach(QModelIndex index, m_bookmarksList)
    {
        QRect bookmarkItemRect = visualRect(m_filterModels[m_currentFilterMode]->mapFromSource(index));
        if(bookmarkItemRect.isValid())
            painter.drawPixmap(2, bookmarkItemRect.bottom() - 16, 16, 16, QPixmap(":/elements/bookmark"));
    }

    if(m_hoveredBranch.isValid())
    {
        QRect toolTipRect(visualRect(m_hoveredBranch).left(), 0, rect().width(), BranchTooltipHeight);
        painter.fillRect(QRect(0, 0, rect().width(), BranchTooltipHeight), QColor(220, 255, 180));
        painter.setPen(QColor(200, 200, 255));
        painter.drawLine(toolTipRect.x() + indentation() / 2, BranchTooltipHeight,
                         toolTipRect.x() + indentation() / 2, mapFromGlobal(QCursor::pos()).y());
        TreeViewDelegate::drawItem(m_hoveredBranch, &painter, toolTipRect);
    }
}

int TreeView::maxRowWidth()
{
    return m_maxItemWidth;
}

TreeViewModel * TreeView::treeViewModel() const
{
    return m_model;
}

void TreeView::setTreeViewModel(TreeViewModel * model)
{
    m_model = model;

    TreeViewFilterProxyModel * filterModel;

    filterModel = new TreeViewFilterProxyModel(TreeViewFilterProxyModel::ShowAllWorkflow, this);
    filterModel->setSourceModel(model);
    m_filterModels.insert(TreeViewFilterProxyModel::ShowAllWorkflow, filterModel);

    filterModel = new TreeViewFilterProxyModel(TreeViewFilterProxyModel::HideEmptyWorkflow, this);
    filterModel->setSourceModel(model);
    m_filterModels.insert(TreeViewFilterProxyModel::HideEmptyWorkflow, filterModel);

    filterModel = new TreeViewFilterProxyModel(TreeViewFilterProxyModel::HideInternalWorkflow, this);
    filterModel->setSourceModel(model);
    m_filterModels.insert(TreeViewFilterProxyModel::HideInternalWorkflow, filterModel);

    setModel(m_filterModels.value(TreeViewFilterProxyModel::ShowAllWorkflow));

    m_maxItemWidth = findMaxItemWidth();
    header()->resizeSection(0, m_maxItemWidth + 50);
}

void TreeView::generateScreenPos()
{
    QModelIndex topIndex = indexAt(QPoint(LeftMarginWidget::marginWidth + 1, 0));
    QModelIndex bottomindex = indexAt(QPoint(LeftMarginWidget::marginWidth + 1, rect().height()));

    emit screenPosChanged(topIndex, bottomindex);
}

DebugTreeFieldIndex TreeView::hoveredField()
{
    return m_hoveredField;
}

DebugTreeFieldIndex TreeView::selectedField()
{
    return m_selectedField;
}

DebugTreeFieldIndexList TreeView::highlightedItems() const
{
    return m_highlightedItems;
}

void TreeView::highlightItems( const DebugTreeFieldIndexList & itemsList )
{
    m_highlightedItems = itemsList;
    repaint();
}

QString TreeView::highlightedField( const QModelIndex & index )
{
    for(int i = 0; i < m_highlightedItems.count(); i++)
        if(TreeViewModel::item(index) == TreeViewModel::item(m_highlightedItems.at(i).itemIndex()))
            return m_highlightedItems.at(i).propertyName();

    return QString();
}

void TreeView::removeHighlight()
{
    m_highlightedItems.clear();
    repaint();
}

const QModelIndexList & TreeView::bookmarkList() const
{
    return m_bookmarksList;
}

void TreeView::checkHoveredItems()
{
    QPoint mousePos = mapFromGlobal(QCursor::pos());
    QModelIndex itemIndex = indexAt(mousePos);

    QSize itemVisualSize = TreeViewDelegate::itemVisualSize(itemIndex);
    QRect itemVisualRect = QRect(visualRect(itemIndex).topLeft(), itemVisualSize);
    bool mouseInsideItem = itemVisualRect.contains(mousePos);

    if((itemIndex != m_hoveredField.itemIndex()) || (m_hoveredField.isValid() && !mouseInsideItem))
    {
        QRect oldHoveredItemRect = visualRect(m_hoveredField.itemIndex());
        m_hoveredField = DebugTreeFieldIndex();
        repaint(oldHoveredItemRect);
    }

    if(/*(itemIndex != m_hoveredField.itemIndex()) && */mouseInsideItem)
    {
        m_hoveredField =
                DebugTreeFieldIndex(itemIndex, TreeViewDelegate::fieldPropertyName(itemIndex,
                                    mousePos.x() - itemVisualRect.left(),
                                    mousePos.y() - itemVisualRect.top()));
        repaint(visualRect(m_hoveredField.itemIndex()));
    }

    bool branchFound = false;
    QModelIndex branchItemIndex;
    QModelIndex oldHoveredBrach = m_hoveredBranch;

    if(!mouseInsideItem)
    {
        QRect itemExpandRect(itemVisualRect.left() - indentation(), itemVisualRect.top(),
                             indentation(), itemVisualRect.height());
        if(!(m_model->hasChildren(itemIndex) && itemExpandRect.contains(mousePos)))
        {
            if(itemVisualRect.left() > mousePos.x() &&
               (itemVisualRect.left() - mousePos.x() - indentation() / 4) % indentation() <
               indentation() / 2)
            {
                int branchLevel = (itemVisualRect.left() - mousePos.x() - indentation() / 4) / indentation() + 1;
                branchItemIndex = itemIndex;
                while(branchLevel--)
                    branchItemIndex = branchItemIndex.parent();

                if(visualRect(branchItemIndex).bottom() < 0)
                {
                    m_hoveredBranch = branchItemIndex;
                    branchFound = true;
                }
            }
        }
    }

    if(!branchFound && m_hoveredBranch.isValid())
        m_hoveredBranch = QModelIndex();

    if(oldHoveredBrach.isValid())
    {
        int oldBranchX = visualRect(oldHoveredBrach).left();
        repaint(oldBranchX, 0, indentation(), rect().height());
    }

    if(m_hoveredBranch.isValid())
    {
        int newBranchX = visualRect(m_hoveredBranch).left();
        repaint(newBranchX, 0, indentation(), rect().height());
    }

    if(oldHoveredBrach.isValid() || m_hoveredBranch.isValid())
        repaint(0, 0, rect().width(), BranchTooltipHeight + 2);
}

QRect TreeView::myVisualRect( const QModelIndex & index )
{
    QModelIndex resultIndex = index;

    while(!visualRect(resultIndex).isValid() && resultIndex.isValid())
        resultIndex = resultIndex.parent();

    if(resultIndex.isValid())
        return visualRect(resultIndex);

    return QRect();
}

void TreeView::updateStyleGeometry()
{
    QFontMetrics fontMetrics(QFont(g_Settings.fontFamily(), g_Settings.fontSize()));
    m_model->setTreeViewHeight(fontMetrics.height());
}

int TreeView::scaleSize() const
{
    return m_scaleSize;
}

void TreeView::setScaleSize( int size )
{
    if(size < 20)
        m_scaleSize = size;
    else
        m_scaleSize = 40 - size;

    QRect highlightRect = visualRect(m_highlightedItem);
    highlightRect.setLeft(0);
    if(size == 40)
        m_highlightedItem = QModelIndex();

    repaint(highlightRect);
}

QModelIndex TreeView::highlightItem()
{
    return m_highlightedItem;
}

void TreeView::setHighlightedItem( const QModelIndex & index )
{
    m_highlightedItem = index;
}

TreeViewFilterProxyModel::FilterMode TreeView::filterMode() const
{
    return m_currentFilterMode;
}

void TreeView::itemUnderMouseChanged( ARSExecItem * item )
{
    //m_itemUnderMouse = item;
}

void TreeView::gotoItem( const QModelIndex & index, bool centerItem, bool ignoreVisibility )
{
    QModelIndex myIndex = m_filterModels.value(m_currentFilterMode)->mapFromSource(index);
    if(!myIndex.isValid())
    {
        if(ignoreVisibility)
        {
            QModelIndex parentIndex = index;
            while((!myIndex.isValid()) && parentIndex.isValid())
            {
                parentIndex = parentIndex.parent();
                myIndex = m_filterModels.value(m_currentFilterMode)->mapFromSource(parentIndex);
            }
        }
        else
        {
            QMessageBox::information(this, tr("Cannot Go To Item"), tr("Item is hidden. Select less strict filtering mode."));
            return;
        }
    }

    int currVal = verticalScrollBar()->value();
    QRect vRect = visualRect(myIndex);
    while(!vRect.isValid() && myIndex.isValid())
    {
        ARSExecItem * item = m_model->item(myIndex);
        item = item->previousItem();
        myIndex = m_model->index(item);
        vRect = visualRect(myIndex);
    }

    int newVal = visualRect(myIndex).top();
    if(centerItem)
        verticalScrollBar()->setValue(currVal + newVal - height() / 2);
    else
        verticalScrollBar()->setValue(currVal + newVal);
}

void TreeView::animateItem( const QModelIndex & index )
{
    m_highlightedItem = index;
    QPropertyAnimation * animation = new QPropertyAnimation(this);
    animation->setTargetObject(this);
    animation->setPropertyName("scaleSize");
    animation->setStartValue(0);
    animation->setEndValue(40);
    animation->setDuration(300);
    animation->start();
}

void TreeView::copyItem()
{
    if(!m_selectedField.isValid())
        return;

    QClipboard * clipBoard = QApplication::clipboard();
    clipBoard->setText(TreeViewDelegate::field2String(TreeViewModel::item(m_selectedField.itemIndex()), m_selectedField.propertyName()));
}

void TreeView::setFilterMode( TreeViewFilterProxyModel::FilterMode mode )
{
    QModelIndex topItemIndex = indexAt(QPoint(viewport()->width() - 5, 5));
    setModel(m_filterModels.value(mode));
    m_currentFilterMode = mode;
    expandAll();
    gotoItem(topItemIndex, false, true);
}

int TreeView::findMaxItemWidth()
{
    int maxWidth = 0;
    ARSExecItem * item = m_model->dynamicModel()->rootItem();
    while(item)
    {
        int width = TreeViewDelegate::itemVisualSize(m_model->index(item)).width();
        if(width > maxWidth)
            maxWidth = width;

        item = item->nextItem();
    }

    return maxWidth;
}

///////// Class 'TreeViewDelegate' implementation //////////////////////////////////////////////////

TreeViewDelegate::TreeViewDelegate( TreeView * parent )
                : QItemDelegate(parent)
{
    m_parentView = parent;
}

void TreeViewDelegate::paint( QPainter * painter,
                              const QStyleOptionViewItem & option,
                              const QModelIndex & index ) const
{
    painter->fillRect(option.rect, Qt::white);
    int scale = 0;
    QString hoveredFieldName;
    QString selectedFieldName;
    if(m_parentView->hoveredField().itemIndex() == index)
        hoveredFieldName = m_parentView->hoveredField().propertyName();

    if(index == m_parentView->highlightItem())
        scale = m_parentView->scaleSize();

    if(m_parentView->selectedField().itemIndex() == index)
        selectedFieldName = m_parentView->selectedField().propertyName();

    QRect boundingRect;
    QRect itemRect(0, 0, option.rect.width(), option.rect.height());
    ARSExecItem * item = TreeViewModel::item(index);
    if(!item)
    {
        qDebug("TreeViewDelegate::drawItem: item is NULL!!!");
        return;
    }

    const QMetaObject * itemMetaObject = item->metaObject();
    int alpha = 255;
    if((item->type() == ARSExecItem::ItemTypeWorkflowObject) &&
        !item->hasChildren())
    {
        alpha = 100;
    }

    painter->save();
    painter->translate(option.rect.x(), option.rect.y());

    if(!item->comment().isEmpty())
    {
        TextStyle * commentStyle = g_Settings.itemStyle("ARSExecItem")->exclusiveStyle(1);
        TextStyle::adjustPainter(painter, commentStyle);
        painter->drawText(itemRect, Qt::AlignLeft | Qt::AlignTop,
                          item->comment(), &boundingRect);
        QColor commentBgColor = commentStyle->fgColor();
        commentBgColor.setAlpha(10);
        QPainterPath path;
        path.addRoundedRect(boundingRect, 3, 3);
        painter->fillPath(path, commentBgColor);
        commentBgColor.setAlpha(100);
        painter->setPen(commentBgColor);
        painter->drawPath(path);
        itemRect.setTop(boundingRect.bottom());
    }

    ItemStyle * itemStyle = g_Settings.itemStyle(itemMetaObject->className());
    QList<PropertyStyle *> propertyStylesList = itemStyle->propertyStyles(ItemStyle::IncludeInherited);
    QString highlightedField = m_parentView->highlightedField(index);
    HighlightRole highlightRole;

    foreach(PropertyStyle * propertyStyle, propertyStylesList)
    {
        if(!selectedFieldName.isNull() && (propertyStyle->name() == selectedFieldName))
            highlightRole = HighlightSelected;
        else
            if(!hoveredFieldName.isNull() && (propertyStyle->name() == hoveredFieldName))
                highlightRole = HighlightHovered;
            else
                if(!highlightedField.isNull() && (propertyStyle->name() == highlightedField))
                    highlightRole = HighlightSearchResult;
                else
                    highlightRole = HighlightNone;

        boundingRect = drawField(painter, item, propertyStyle->name(),
                                 itemRect, propertyStyle, highlightRole, alpha);
        itemRect.setLeft(boundingRect.right());
    }

    painter->restore();
}

QSize TreeViewDelegate::sizeHint( const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
    return itemVisualSize(index);
}

void TreeViewDelegate::drawItem( const QModelIndex & index, QPainter * painter,
                                 const QRect & rect, bool singleLine )
{
    QRect boundingRect;
    QRect itemRect(0, 0, rect.width(), rect.height());
    ARSExecItem * item = TreeViewModel::item(index);
    if(!item)
    {
        qDebug("TreeViewDelegate::drawItem: item is NULL!!!");
        return;
    }

    const QMetaObject * itemMetaObject = item->metaObject();

    painter->save();
    painter->translate(rect.x(), rect.y());

//    if(scale != 0)
//    {
//        QSize vSize = itemVisualSize(index);
//        qreal realScale = (qreal)(vSize.width() + scale) / (qreal)vSize.width();
//        painter->translate(-scale / 2, 0);
//        painter->scale(realScale, 1);
//    }

    if(!(item->comment().isEmpty() || singleLine))
    {
        TextStyle * commentStyle = g_Settings.itemStyle("ARSExecItem")->exclusiveStyle(1);
        TextStyle::adjustPainter(painter, commentStyle);
        painter->drawText(itemRect, Qt::AlignLeft | Qt::AlignTop,
                          item->comment(), &boundingRect);
        QColor commentBgColor = commentStyle->fgColor();
        commentBgColor.setAlpha(10);
        QPainterPath path;
        path.addRoundedRect(boundingRect, 3, 3);
        painter->fillPath(path, commentBgColor);
        commentBgColor.setAlpha(100);
        painter->setPen(commentBgColor);
        painter->drawPath(path);
        itemRect.setTop(boundingRect.bottom());
    }

    ItemStyle * itemStyle = g_Settings.itemStyle(itemMetaObject->className());
    QList<PropertyStyle *> propertyStylesList = itemStyle->propertyStyles(ItemStyle::IncludeInherited);
    foreach(PropertyStyle * propertyStyle, propertyStylesList)
    {
        boundingRect = drawField(painter, item, propertyStyle->name(),
                                 itemRect, propertyStyle);
        itemRect.setLeft(boundingRect.right());
    }

    painter->restore();
}

QRect TreeViewDelegate::drawField( QPainter * painter, ARSExecItem * item, const QString & propertyName,
                                   QRect rect, PropertyStyle * propertyStyle, HighlightRole highlightRole, int alpha)
{
    QVariant propertyValue = item->property(qPrintable(propertyName));
    ARSDummyObject * arsObject = 0;
    TextStyle * headerStyle = g_Settings.itemStyle("ARSExecItem")->exclusiveStyle(0);
    QRect itemRect = rect;
    QRect boundingRect;
    QString propertyLabelString;
    QString propertyValueString;

    if(highlightRole == HighlightHovered)
    {
        QRect highlightRect = QRect(rect.topLeft(), fieldSize(item, propertyName)).adjusted(0, 0, -1, -1);
        QPainterPath painterPath;
        painterPath.addRoundedRect(highlightRect, 3, 3);
        painter->fillPath(painterPath, QColor(80, 80, 170, 30));
    }

    if(highlightRole == HighlightSelected)
    {
        QRect highlightRect = QRect(rect.topLeft(), fieldSize(item, propertyName)).adjusted(0, 0, -1, -1);
        QPainterPath painterPath;
        painterPath.addRoundedRect(highlightRect, 3, 3);
        painter->setRenderHint(QPainter::Antialiasing);
        painter->fillPath(painterPath, QColor(80, 80, 170));
        painter->setRenderHint(QPainter::Antialiasing, false);
    }

    if(highlightRole == HighlightSearchResult)
    {
        QRect highlightRect = QRect(rect.topLeft(), fieldSize(item, propertyName)).adjusted(0, 0, -1, -1);
        QPainterPath painterPath;
        painterPath.addRoundedRect(highlightRect, 3, 3);
        painter->setRenderHint(QPainter::Antialiasing);
        painter->fillPath(painterPath, QColor(80, 170, 0));
        painter->setRenderHint(QPainter::Antialiasing, false);
    }

    if(!propertyStyle)
        return QRect(rect.topLeft(), rect.bottomLeft());

    PropertyStyleBase * valueStyle = propertyStyle;

    propertyLabelString = propertyStyle->label();

    if(propertyStyle->hasAliasStyles())
    {
        PropertyAliasStyle * propertyAliasStyle = propertyStyle->styleForValue(propertyValue);

        if(propertyAliasStyle)
        {
            valueStyle = propertyAliasStyle;
            propertyValueString = propertyAliasStyle->alias();
        }
    }

    if(propertyValueString.isNull())
    {
        if(propertyValue.canConvert(QVariant::String))
            propertyValueString = propertyValue.toString();
        else
        {
            arsObject = ARSDummyObject::toARSObject(propertyValue);

            if(arsObject)
                propertyValueString = arsObject->name();
            else
                propertyValueString = propertyStyle->name() + ": object is null";
        }
    }

    if(valueStyle && valueStyle->visibility() != PropertyStyle::Hidden)
    {
        if(propertyStyle->visibility() == PropertyStyle::Visible)
        {
            TextStyle::adjustPainter(painter, headerStyle);
            if(highlightRole == HighlightSelected || highlightRole == HighlightSearchResult)
                painter->setPen(Qt::white);
            else
                if(alpha < 255)
                {
                    QColor color = painter->pen().color();
                    color.setAlpha(alpha);
                    painter->setPen(color);
                }
            painter->drawText(rect, Qt::AlignLeft | Qt::AlignTop,
                              propertyLabelString + propertyStyle->separator() + " ", &boundingRect);

            itemRect.setLeft(boundingRect.right());
        }

        TextStyle::adjustPainter(painter, valueStyle);
        if(highlightRole == HighlightSelected || highlightRole == HighlightSearchResult)
            painter->setPen(Qt::white);
        else
            if(alpha < 255)
            {
                QColor color = painter->pen().color();
                color.setAlpha(alpha);
                painter->setPen(color);
            }

        painter->drawText(itemRect, Qt::AlignLeft | Qt::AlignTop,
                          propertyValueString, &boundingRect);

        itemRect.setLeft(boundingRect.right() + SpacingInsideProperty);
    }

    boundingRect = QRect(rect.topLeft(), itemRect.bottomLeft());

    return boundingRect;
}

QSize TreeViewDelegate::itemVisualSize( const QModelIndex & index, bool singleLine )
{
    QFontMetrics defaultFontMetrics(g_Settings.itemStyle("ARSExecItem")->font());
    QSize itemSize(0, defaultFontMetrics.height());
    ARSExecItem * item = TreeViewModel::item(index);
    if(!item)
    {
        qDebug("TreeViewDelegate::drawItem: item is NULL!!!");
        return QSize();
    }

    const QMetaObject * itemMetaObject = item->metaObject();
    QString propertyLabelString;
    QString propertyValueString;
    QFontMetrics fontMetrics(QFont(g_Settings.fontFamily(), g_Settings.fontSize()));
    int fontHeight = fontMetrics.height();

    if(!(item->comment().isEmpty() || singleLine))
    {
        int lineCount = item->comment().count('\n') + 1;
        itemSize.setHeight(itemSize.height() + lineCount * fontHeight);
    }

    ItemStyle * itemStyle = g_Settings.itemStyle(itemMetaObject->className());
    QList<PropertyStyle *> propertyStylesList = itemStyle->propertyStyles(ItemStyle::IncludeInherited);
    foreach(PropertyStyle * propertyStyle, propertyStylesList)
    {
        QVariant propertyValue = item->property(qPrintable(propertyStyle->name()));
        ARSDummyObject * arsObject = 0;

        PropertyStyleBase * valueStyle = propertyStyle;
        propertyValueString = QString();
        if(propertyStyle)
        {
            propertyLabelString = propertyStyle->label();

            if(propertyStyle->hasAliasStyles())
            {
                PropertyAliasStyle * propertyAliasStyle = propertyStyle->styleForValue(propertyValue);

                if(propertyAliasStyle)
                {
                    valueStyle = propertyAliasStyle;
                    propertyValueString = propertyAliasStyle->alias();
                }
            }

            if(propertyValueString.isNull())
            {
                if(propertyValue.canConvert(QVariant::String))
                    propertyValueString = propertyValue.toString();
                else
                {
                    arsObject = ARSDummyObject::toARSObject(propertyValue);

                    if(arsObject)
                        propertyValueString = arsObject->name();
                    else
                        propertyValueString = "object is null";
                }
            }

            if(valueStyle && valueStyle->visibility() != PropertyStyle::Hidden)
            {
                if(propertyStyle->visibility() == PropertyStyle::Visible)
                {
                    itemSize.setWidth(itemSize.width() +
                                      fontMetrics.boundingRect(propertyLabelString + propertyStyle->separator() + " ").width());
                }

                itemSize.setWidth(itemSize.width() + fontMetrics.boundingRect(propertyValueString).width() + SpacingInsideProperty);
            }
        }
    }

    return itemSize;
}

QString TreeViewDelegate::item2String( const ARSExecItem * item )
{
    QString itemString;

    if(!item)
    {
        qDebug("TreeViewDelegate::item2String: item is NULL!!!");
        return QString::null;
    }

    const QMetaObject * itemMetaObject = item->metaObject();
    QString propertyLabelString;
    QString propertyValueString;

    ItemStyle * itemStyle = g_Settings.itemStyle(itemMetaObject->className());
    QList<PropertyStyle *> propertyStylesList = itemStyle->propertyStyles(ItemStyle::IncludeInherited);
    foreach(PropertyStyle * propertyStyle, propertyStylesList)
    {
        QVariant propertyValue = item->property(qPrintable(propertyStyle->name()));
        ARSDummyObject * arsObject = 0;

        PropertyStyleBase * valueStyle = propertyStyle;
        propertyValueString = QString();
        if(propertyStyle)
        {
            propertyLabelString = propertyStyle->label();

            if(propertyStyle->hasAliasStyles())
            {
                PropertyAliasStyle * propertyAliasStyle = propertyStyle->styleForValue(propertyValue);

                if(propertyAliasStyle)
                {
                    valueStyle = propertyAliasStyle;
                    propertyValueString = propertyAliasStyle->alias();
                }
            }

            if(propertyValueString.isNull())
            {
                if(propertyValue.canConvert(QVariant::String))
                    propertyValueString = propertyValue.toString();
                else
                {
                    arsObject = ARSDummyObject::toARSObject(propertyValue);

                    if(arsObject)
                        propertyValueString = arsObject->name();
                    else
                        propertyValueString = propertyStyle->name() + ": object is null";
                }
            }

            if(valueStyle && valueStyle->visibility() != PropertyStyle::Hidden)
            {
                if(propertyStyle->visibility() == PropertyStyle::Visible)
                    itemString += propertyLabelString + propertyStyle->separator() + " ";

                itemString += propertyValueString + " ";
            }
        }
    }

    return itemString;
}

QString TreeViewDelegate::field2String( const ARSExecItem * item, const QString propertyName )
{
    if(!item)
    {
        qDebug("TreeViewDelegate::item2String: item is NULL!!!");
        return QString::null;
    }

    QString fieldString;
    const QMetaObject * itemMetaObject = item->metaObject();
    QString propertyLabelString;
    QString propertyValueString;
    ItemStyle * itemStyle = g_Settings.itemStyle(itemMetaObject->className());
    PropertyStyle * propertyStyle = itemStyle->propertyStyle(propertyName);
    QVariant propertyValue = item->property(qPrintable(propertyStyle->name()));
    ARSDummyObject * arsObject = 0;

    PropertyStyleBase * valueStyle = propertyStyle;
    propertyValueString = QString();
    if(propertyStyle)
    {
        propertyLabelString = propertyStyle->label();

        if(propertyStyle->hasAliasStyles())
        {
            PropertyAliasStyle * propertyAliasStyle = propertyStyle->styleForValue(propertyValue);

            if(propertyAliasStyle)
            {
                valueStyle = propertyAliasStyle;
                propertyValueString = propertyAliasStyle->alias();
            }
        }

        if(propertyValueString.isNull())
        {
            if(propertyValue.canConvert(QVariant::String))
                propertyValueString = propertyValue.toString();
            else
            {
                arsObject = ARSDummyObject::toARSObject(propertyValue);

                if(arsObject)
                    propertyValueString = arsObject->name();
                else
                    propertyValueString = propertyStyle->name() + ": object is null";
            }
        }

        if(valueStyle && valueStyle->visibility() != PropertyStyle::Hidden)
        {
            if(propertyStyle->visibility() == PropertyStyle::Visible)
                fieldString += propertyLabelString + propertyStyle->separator() + " ";

            fieldString += propertyValueString;
        }
    }

    return fieldString;
}

QString TreeViewDelegate::fieldPropertyName( const QModelIndex & index, int dx, int dy, bool singleLine )
{
    QFontMetrics defaultFontMetrics(g_Settings.itemStyle("ARSExecItem")->font());
    QSize itemSize(0, defaultFontMetrics.height());
    ARSExecItem * item = TreeViewModel::item(index);
    if(!item)
    {
        qDebug("TreeViewDelegate::fieldPropertyName: item is NULL!!!");
        return QString();
    }

    const QMetaObject * itemMetaObject = item->metaObject();
    QString propertyLabelString;
    QString propertyValueString;
    QFontMetrics fontMetrics(QFont(g_Settings.fontFamily(), g_Settings.fontSize()));
    int fontHeight = fontMetrics.height();

    if(!(item->comment().isEmpty() || singleLine))
    {
        int lineCount = item->comment().count('\n') + 1;
        itemSize.setHeight(itemSize.height() + lineCount * fontHeight);
    }

    if(itemSize.width() > dx && itemSize.height() > dy)
        return "comment";

    ItemStyle * itemStyle = g_Settings.itemStyle(itemMetaObject->className());
    QList<PropertyStyle *> propertyStylesList = itemStyle->propertyStyles(ItemStyle::IncludeInherited);
    foreach(PropertyStyle * propertyStyle, propertyStylesList)
    {
        QVariant propertyValue = item->property(qPrintable(propertyStyle->name()));
        ARSDummyObject * arsObject = 0;

        PropertyStyleBase * valueStyle = propertyStyle;
        propertyValueString = QString();
        if(propertyStyle)
        {
            propertyLabelString = propertyStyle->label();

            if(propertyStyle->hasAliasStyles())
            {
                PropertyAliasStyle * propertyAliasStyle = propertyStyle->styleForValue(propertyValue);

                if(propertyAliasStyle)
                {
                    valueStyle = propertyAliasStyle;
                    propertyValueString = propertyAliasStyle->alias();
                }
            }

            if(propertyValueString.isNull())
            {
                if(propertyValue.canConvert(QVariant::String))
                    propertyValueString = propertyValue.toString();
                else
                {
                    arsObject = ARSDummyObject::toARSObject(propertyValue);

                    if(arsObject)
                        propertyValueString = arsObject->name();
                    else
                        propertyValueString = "object is null";
                }
            }

            if(valueStyle && valueStyle->visibility() != PropertyStyle::Hidden)
            {
                if(propertyStyle->visibility() == PropertyStyle::Visible)
                {
                    itemSize.setWidth(itemSize.width() +
                                      fontMetrics.boundingRect(propertyLabelString + propertyStyle->separator() + " ").width());
                }

                itemSize.setWidth(itemSize.width() + fontMetrics.boundingRect(propertyValueString).width() + SpacingInsideProperty);
            }
        }

        if(itemSize.width() > dx && itemSize.height() > dy)
            return propertyStyle->name();
    }

    return QString();
}

QSize TreeViewDelegate::fieldSize( const ARSExecItem * item, const QString propertyName, bool singleLine )
{
    QFontMetrics defaultFontMetrics(g_Settings.itemStyle("ARSExecItem")->font());
    bool isCorrentProperty = false;
    QRect boundingRect;
    QSize resultSize(0, defaultFontMetrics.height());

    if(!item)
    {
        qDebug("TreeViewDelegate::fieldPropertyName: item is NULL!!!");
        return QSize();
    }

    const QMetaObject * itemMetaObject = item->metaObject();
    QString propertyLabelString;
    QString propertyValueString;
    QFontMetrics fontMetrics(QFont(g_Settings.fontFamily(), g_Settings.fontSize()));

    ItemStyle * itemStyle = g_Settings.itemStyle(itemMetaObject->className());
    PropertyStyle * propertyStyle = itemStyle->propertyStyle(propertyName);
    QVariant propertyValue = item->property(qPrintable(propertyStyle->name()));
    ARSDummyObject * arsObject = 0;

    PropertyStyleBase * valueStyle = propertyStyle;
    propertyValueString = QString();
    if(propertyStyle)
    {
        propertyLabelString = propertyStyle->label();

        if(propertyStyle->hasAliasStyles())
        {
            PropertyAliasStyle * propertyAliasStyle = propertyStyle->styleForValue(propertyValue);

            if(propertyAliasStyle)
            {
                valueStyle = propertyAliasStyle;
                propertyValueString = propertyAliasStyle->alias();
            }
        }

        if(propertyValueString.isNull())
        {
            if(propertyValue.canConvert(QVariant::String))
                propertyValueString = propertyValue.toString();
            else
            {
                arsObject = ARSDummyObject::toARSObject(propertyValue);

                if(arsObject)
                    propertyValueString = arsObject->name();
                else
                    propertyValueString = "object is null";
            }
        }

        if(propertyStyle->name() == propertyName)
            isCorrentProperty = true;

        if(valueStyle && valueStyle->visibility() != PropertyStyle::Hidden)
        {
            if(propertyStyle->visibility() == PropertyStyle::Visible)
            {
                boundingRect = fontMetrics.boundingRect(propertyLabelString + propertyStyle->separator() + " ");
                resultSize.setWidth(boundingRect.width() + SpacingInsideProperty);
            }

            resultSize.setWidth(resultSize.width() + fontMetrics.boundingRect(propertyValueString).width());
        }
    }

    return resultSize;
}

/*
QWidget * TreeViewDelegate::createEditor( QWidget * parent, const QStyleOptionViewItem & option,
                                          const QModelIndex & index ) const
{
    CommentEditWidget * commentEdit = new CommentEditWidget(parent);
    return commentEdit;
}

void TreeViewDelegate::setEditorData( QWidget * editor, const QModelIndex & index ) const
{
    CommentEditWidget * commentEdit = static_cast<CommentEditWidget *>(editor);
    ARSExecItem * item = TreeViewModel::item(index);
    commentEdit->setText(item->comment());
}

void TreeViewDelegate::setModelData( QWidget * editor, QAbstractItemModel * model, const QModelIndex & index ) const
{
    CommentEditWidget * commentEdit = static_cast<CommentEditWidget *>(editor);
    model->setData(index, commentEdit->text(), Qt::EditRole);
}

void TreeViewDelegate::updateEditorGeometry( QWidget * editor, const QStyleOptionViewItem & option,
                                             const QModelIndex & index ) const
{
    editor->move(option.rect.topLeft());
} */

///////// Class 'BranchScrollerWidget' declaration /////////////////////////////////////////////////

BranchScrollerWidget::BranchScrollerWidget( QWidget * parent )
    : QWidget(parent)
{
    setFixedSize(scrollerWidth, scrollerHeight);
//    m_frame = frame;
}

//BranchFrame BranchScrollerWidget::frame()
//{
//    return m_frame;
//}

void BranchScrollerWidget::paintEvent( QPaintEvent * event )
{
    QPainter painter(this);
    painter.fillRect(rect(), QColor(240, 240, 240));
    painter.setPen(QColor(160, 160, 160));
    painter.drawRect(rect().adjusted(0, 0, -1, -1));
    painter.setPen(QColor(200, 200, 200));
    painter.drawLine(rect().left() + 2, rect().center().y(),
                     rect().right() - 2, rect().center().y());
}

///////// Class 'DockTitleLabel' implementation ///////////////////////////////////////////////////

DockTitleLabel::DockTitleLabel( QWidget * parent )
    : QWidget(parent)
{
}

void DockTitleLabel::setText( const QString & text )
{
    m_text = text;
    repaint();
}

void DockTitleLabel::paintEvent( QPaintEvent * event )
{
    QPainter painter(this);

    QRect widgetRect = rect();
    painter.fillRect(widgetRect, QColor(220, 220, 220));
    painter.translate(widgetRect.width(), 0);
    painter.rotate(90);
//    painter.setPen(QColor(230, 230, 230));
    painter.drawText(0, 0, widgetRect.height(), widgetRect.width(), Qt::AlignCenter, m_text);
}

///////// Class 'DockTitleWidget' implementation ////////////////////////////////////////////////////////

DockTitleWidget::DockTitleWidget(QWidget * parent)
    : QWidget(parent)
{
    QVBoxLayout * mainLayout = new QVBoxLayout(this);
    mainLayout->setContentsMargins(3, 0, 0, 3);
    mainLayout->setSpacing(0);

    m_title = new DockTitleLabel(this);
    mainLayout->addWidget(m_title, 1);
    m_closeButton = new QToolButton(this);
    m_closeButton->setFixedSize(14, 14);
    connect(m_closeButton, SIGNAL(clicked()), this, SIGNAL(closeClicked()));
    mainLayout->addWidget(m_closeButton);

    setLayout(mainLayout);
    setFixedWidth(MarginWidth);
}

void DockTitleWidget::paintEvent( QPaintEvent * event )
{
    QPainter painter(this);
    QRect widgetRect = rect();
    painter.fillRect(widgetRect, QColor(220, 220, 220));
}

void DockTitleWidget::setText( const QString & text )
{
    m_title->setText(text);
}

///////// Class 'DockWidget' implementation ////////////////////////////////////////////////////////

DockWidget::DockWidget( QWidget * parent )
    : QWidget(parent)
{
    QHBoxLayout * mainLayout = new QHBoxLayout(this);
    mainLayout->setContentsMargins(0, 0, 0, 0);
    mainLayout->setSpacing(0);

    m_title = new DockTitleWidget(this);
    connect(m_title, SIGNAL(closeClicked()), this, SIGNAL(closeClicked()));
    mainLayout->addWidget(m_title);

    m_stack = new QStackedWidget(this);

    m_bookmarksListWidget = new ItemsListWidget(this);
    m_stack->addWidget(m_bookmarksListWidget);

    m_searchResultsListWidget = new ItemsListWidget(this);
    m_stack->addWidget(m_searchResultsListWidget);

    mainLayout->addWidget(m_stack, 1);

    setLayout(mainLayout);

    QFile styleFile(":/qss/dockwidget");
    styleFile.open(QFile::ReadOnly);
    setStyleSheet(styleFile.readAll());
}

void DockWidget::setWidget( DockWidget::Widget widget )
{
    switch(widget)
    {
    case None:
        hide();
        break;

    case Bookmarks:
        m_stack->setCurrentWidget(m_bookmarksListWidget);
        m_title->setText(tr("Bookmarks"));
        break;

    case SearchItems:
//        m_stack->setCurrentWidget(m_searchWidget);
        break;

    case SearchResults:
        m_title->setText(tr("Search Results"));
        m_stack->setCurrentWidget(m_searchResultsListWidget);
        break;
    }

//    m_label->setCurrentWidget(widget);
}

DockWidget::Widget DockWidget::currentWidget()
{
    if(isHidden())
        return None;

    QWidget * widget = m_stack->currentWidget();
    if(widget == m_bookmarksListWidget)
        return Bookmarks;

//    if(widget == m_searchWidget)
//        return SearchItems;

    if(widget == m_searchResultsListWidget)
        return SearchResults;

    return None;
}

ItemsListWidget * DockWidget::bookmarksListWidget()
{
    return m_bookmarksListWidget;
}

//SearchWidget * DockWidget::searchWidget()
//{
//    return m_searchWidget;
//}

ItemsListWidget * DockWidget::searchResultsListWidget()
{
    return m_searchResultsListWidget;
}

void DockWidget::addBookMark( const QModelIndex & index )
{
    m_bookmarksListWidget->addItem(index);
}

void DockWidget::removeBookMark( const QModelIndex & index )
{
    m_bookmarksListWidget->removeItem(index);
}

///////// Class 'TreeViewWidget' declaration ///////////////////////////////////////////////////////

TreeViewWidget::TreeViewWidget(QWidget * parent)
    : DynamicViewWidget(parent)
{
    m_model = 0;
    m_bookmarksAction = 0;

    QVBoxLayout * vLayout = new QVBoxLayout(this);

    vLayout->setSpacing(0);
    vLayout->setContentsMargins(0, 0, 0, 0);

    QSplitter * splitter = new QSplitter(Qt::Vertical, this);

    m_dockWidget = new DockWidget(this);
    connect(m_dockWidget, SIGNAL(closeClicked()), this, SLOT(hideDockWidget()));
    splitter->addWidget(m_dockWidget);
    m_dockWidget->hide();
    connect(m_dockWidget->bookmarksListWidget(), SIGNAL(itemClicked(QModelIndex, bool)),
            this, SLOT(gotoBookmark(QModelIndex, bool)));
    connect(m_dockWidget->searchResultsListWidget(), SIGNAL(itemClicked(QModelIndex, bool)),
            this, SLOT(gotoSearchResult(QModelIndex, bool)));

    m_treeWidget = new TreeView(this);
    connect(m_treeWidget, SIGNAL(bookmarkAdded(QModelIndex)),
            this, SLOT(addBookmarkToDock(QModelIndex)));
    connect(m_treeWidget, SIGNAL(bookmarkRemoved(QModelIndex)),
            this, SLOT(removeBookmarkFromDock(QModelIndex)));
    connect(m_treeWidget, SIGNAL(screenPosChanged(QModelIndex,QModelIndex)),
            this, SLOT(setScreenPos(QModelIndex,QModelIndex)));
    connect(m_treeWidget, SIGNAL(modified()),
            this, SIGNAL(modified()));
    splitter->addWidget(m_treeWidget);

    splitter->setCollapsible(0, false);
    splitter->setCollapsible(1, false);
    splitter->setStretchFactor(1, 2);

//    QList<int> splitterSizes;
//    splitterSizes.append(1);
//    splitterSizes.append(10);
//    splitter->setSizes(splitterSizes);

    QFile styleFile(":/qss/docksplitter");
    styleFile.open(QFile::ReadOnly);
    splitter->setStyleSheet(styleFile.readAll());

    vLayout->addWidget(splitter);
    setLayout(vLayout);
}

void TreeViewWidget::setModel(DynamicModel * model)
{
    m_model = new TreeViewModel(model, this);
    m_treeWidget->setTreeViewModel(m_model);
    m_treeWidget->expandAll();

    ObjectsIndex * index = m_model->dynamicModel()->index();
    m_searchModel = new TreeViewSearchModel(index->objects(ARSObject::Form | ARSObject::Field | ARSObject::ActiveLink | ARSObject::Filter | ARSObject::Guide), this);
}

QString TreeViewWidget::pluginName() const
{
    return "treeview";
}

void TreeViewWidget::connectToolBarItems(const ToolBarItemList &items)
{
    ViewWidget::connectToolBarItems(items);

    foreach(ToolBarItem * item, items)
    {
        if(item->type() == ToolBarItem::Widget && item->objectName() == "search")
        {
            ToolBarWidget * toolBarWidget = qobject_cast<ToolBarWidget *>(item);
            TreeViewSearchWidget * searchWidget = qobject_cast<TreeViewSearchWidget *>(toolBarWidget->widget());
            if(searchWidget)
                connect(searchWidget, SIGNAL(searchObject(ARSDummyObject*)), this, SLOT(searchObject(ARSDummyObject*)));
        }

        if(item->objectName() == "showAllWorkflow")
        {
            QAction * action = item->action();
            connect(action, SIGNAL(toggled(bool)), this, SLOT(showAllWorkflow(bool)));
        }

        if(item->objectName() == "hideEmptyWorkflow")
        {
            QAction * action = item->action();
            connect(action, SIGNAL(toggled(bool)), this, SLOT(hideEmptyWorkflow(bool)));
        }

        if(item->objectName() == "hideInternalWorkflow")
        {
            QAction * action = item->action();
            connect(action, SIGNAL(toggled(bool)), this, SLOT(hideInternalWorkflow(bool)));
        }

        if(item->objectName() == "showBookmarks")
        {
            QAction * action = item->action();
            connect(action, SIGNAL(toggled(bool)), this, SLOT(showBookmarks(bool)));
            m_bookmarksAction = action;
        }
    }
}

void TreeViewWidget::disconnectToolBarItems(const ToolBarItemList &items)
{
    ViewWidget::disconnectToolBarItems(items);

    foreach(ToolBarItem * item, items)
    {
        if(item->type() == ToolBarItem::Widget && item->objectName() == "search")
        {
            ToolBarWidget * toolBarWidget = qobject_cast<ToolBarWidget *>(item);
            TreeViewSearchWidget * searchWidget = qobject_cast<TreeViewSearchWidget *>(toolBarWidget->widget());
            if(searchWidget)
                disconnect(searchWidget, SIGNAL(searchObject(ARSDummyObject*)), this, SLOT(searchObject(ARSDummyObject*)));
        }

        if(item->objectName() == "showAllWorkflow")
        {
            QAction * action = item->action();
            disconnect(action, SIGNAL(toggled(bool)), this, SLOT(showAllWorkflow(bool)));
        }

        if(item->objectName() == "hideEmptyWorkflow")
        {
            QAction * action = item->action();
            disconnect(action, SIGNAL(toggled(bool)), this, SLOT(hideEmptyWorkflow(bool)));
        }

        if(item->objectName() == "hideInternalWorkflow")
        {
            QAction * action = item->action();
            disconnect(action, SIGNAL(toggled(bool)), this, SLOT(hideInternalWorkflow(bool)));
        }

        if(item->objectName() == "showBookmarks")
        {
            QAction * action = item->action();
            disconnect(action, SIGNAL(toggled(bool)), this, SLOT(showBookmarks(bool)));
        }
    }

    m_bookmarksAction = 0;
}

void TreeViewWidget::adjustToolbar(const ToolBarItemList & itemsList) const
{
    foreach(ToolBarItem * item, itemsList)
    {
        if(item->type() == ToolBarItem::Widget && item->objectName() == "search")
        {
            ToolBarWidget * toolBarWidget = qobject_cast<ToolBarWidget *>(item);
            TreeViewSearchWidget * searchWidget = qobject_cast<TreeViewSearchWidget *>(toolBarWidget->widget());
            searchWidget->setModel(m_searchModel);
        }

        if(item->objectName() == "showAllWorkflow" && m_treeWidget->filterMode() == TreeViewFilterProxyModel::ShowAllWorkflow)
            item->action()->setChecked(true);

        if(item->objectName() == "hideEmptyWorkflow" && m_treeWidget->filterMode() == TreeViewFilterProxyModel::HideEmptyWorkflow)
            item->action()->setChecked(true);

        if(item->objectName() == "hideInternalWorkflow" && m_treeWidget->filterMode() == TreeViewFilterProxyModel::HideInternalWorkflow)
            item->action()->setChecked(true);

        if(item->objectName() == "showBookmarks")
            item->action()->setChecked(dockCurrentWidget() == DockWidget::Bookmarks);
    }
}

TreeView * TreeViewWidget::treeWidget()
{
    return m_treeWidget;
}

void TreeViewWidget::showDockWidget( DockWidget::Widget widget )
{
    if(m_dockWidget->currentWidget() == widget)
        return;

    if(m_dockWidget->currentWidget() == DockWidget::None && widget != DockWidget::None)
        m_dockWidget->show();

    m_dockWidget->setWidget(widget);
}

void TreeViewWidget::hideDockWidget()
{
    m_dockWidget->hide();
    m_bookmarksAction->setChecked(false);
}

DockWidget::Widget TreeViewWidget::dockCurrentWidget() const
{
    return m_dockWidget->currentWidget();
}

void TreeViewWidget::searchObject( ARSDummyObject * object )
{
    ARSExecItemList itemsList = m_model->index()->relatedItems(object);
    DebugTreeFieldIndexList fieldsList;
    QModelIndexList itemsIndexList;
    foreach(ARSExecItem * item, itemsList)
    {
        const QMetaObject * itemMetaObject = item->metaObject();
        QString propertyName;
        for(int i = 0; i < itemMetaObject->propertyCount() && propertyName.isNull(); i++)
        {
            ARSDummyObject * arsObject = ARSDummyObject::toARSObject(item->property(itemMetaObject->property(i).name()));
            if(arsObject && arsObject == object)
                propertyName = QString::fromAscii(itemMetaObject->property(i).name());
        }

        QModelIndex itemIndex = m_model->index(item);
        DebugTreeFieldIndex fieldIndex(itemIndex, propertyName);
        itemsIndexList.append(itemIndex);
        fieldsList.append(fieldIndex);
    }

    m_treeWidget->highlightItems(fieldsList);
    int itemsCount = itemsIndexList.size();
    if(itemsCount > 1)
    {
        m_dockWidget->searchResultsListWidget()->setItemsList(itemsIndexList);
        showDockWidget(DockWidget::SearchResults);
    }
    else
    {
        if(m_dockWidget->currentWidget() == DockWidget::SearchResults)
            m_dockWidget->hide();

        gotoSearchResult(itemsIndexList.first(), false);
    }
}

void TreeViewWidget::keyPressEvent( QKeyEvent * event )
{
    if(event->key() == Qt::Key_Escape)
    {
        if(m_dockWidget->currentWidget() != DockWidget::None)
        {
            hideDockWidget();
        }
        else
        {
            if(!m_treeWidget->highlightedItems().isEmpty())
                m_treeWidget->removeHighlight();
        }
    }
}

void TreeViewWidget::showObjectDetails( const ARSObject * object )
{
    /*m_objectWidget->setObject(object);

    if(m_objectWidget->isHidden())
        m_objectWidget->show();*/
}

void TreeViewWidget::commentAdded()
{
    //m_addCommentAction->setChecked(false);
}

void TreeViewWidget::commentFocusTypeChanged( TreeView::EditItemType type )
{
    /*if(type == DebugTreeView::Comment)
        deleteCommentAction->setEnabled(true);
    else
        deleteCommentAction->setEnabled(false);*/
}

void TreeViewWidget::addBookmarkToDock( const QModelIndex & index )
{
    m_dockWidget->addBookMark(index);
}

void TreeViewWidget::removeBookmarkFromDock( const QModelIndex & index )
{
    m_dockWidget->removeBookMark(index);
}

void TreeViewWidget::gotoBookmark( const QModelIndex & index, bool closeList )
{
    m_treeWidget->gotoItem(index);

    if(closeList)
        showDockWidget(DockWidget::None);
}

void TreeViewWidget::gotoSearchResult( const QModelIndex & index, bool closeList )
{
    m_treeWidget->gotoItem(index);

    if(closeList)
        showDockWidget(DockWidget::None);
}

void TreeViewWidget::setScreenPos( const QModelIndex & top, const QModelIndex & bottom )
{
    m_dockWidget->bookmarksListWidget()->setScreenPos(top, bottom);
    m_dockWidget->searchResultsListWidget()->setScreenPos(top, bottom);
}

void TreeViewWidget::gotoItem( ARSExecItem * item )
{
    m_treeWidget->gotoItem(m_model->index(item));
}

void TreeViewWidget::expand()
{
    m_treeWidget->expandAll();
}

void TreeViewWidget::collapse()
{
    m_treeWidget->collapseAll();
}

void TreeViewWidget::showAllWorkflow(bool yes)
{
    if(yes)
        m_treeWidget->setFilterMode(TreeViewFilterProxyModel::ShowAllWorkflow);
}

void TreeViewWidget::hideEmptyWorkflow(bool yes)
{
    if(yes)
        m_treeWidget->setFilterMode(TreeViewFilterProxyModel::HideEmptyWorkflow);
}

void TreeViewWidget::hideInternalWorkflow(bool yes)
{
    if(yes)
        m_treeWidget->setFilterMode(TreeViewFilterProxyModel::HideInternalWorkflow);
}

void TreeViewWidget::copyItem()
{
    m_treeWidget->copyItem();
}

void TreeViewWidget::showBookmarks(bool show)
{
    if(show)
        showDockWidget(DockWidget::Bookmarks);
    else
        hideDockWidget();
}

///////// Class 'CommentEditDialog' implementation /////////////////////////////////////////////

CommentEditDialog::CommentEditDialog( QWidget * parent )
    : QDialog(parent)
{
    setWindowTitle(tr("Edit Comment"));
    QFile styleFile(g_Settings_skin_dir + "/custom.qss");
    styleFile.open(QIODevice::ReadOnly);
    setStyleSheet(styleFile.readAll());
    styleFile.close();

    QVBoxLayout * mainLayout = new QVBoxLayout(this);
    mainLayout->setContentsMargins(0, 0, 0, 0);
    m_edit = new QTextEdit(this);
    m_edit->installEventFilter(this);
    mainLayout->addWidget(m_edit);

    QHBoxLayout * buttonsLayout = new QHBoxLayout(this);
    QPushButton * button = new QPushButton(tr("Accept"), this);
    button->setIcon(QIcon(g_Settings_skin_dir + "/accept.png"));
    connect(button, SIGNAL(clicked()), this, SLOT(accept()));
    buttonsLayout->addWidget(button);
    button = new QPushButton(tr("Close"), this);
    button->setIcon(QIcon(g_Settings_skin_dir + "/close.png"));
    connect(button, SIGNAL(clicked()), this, SLOT(reject()));
    buttonsLayout->addWidget(button);
    buttonsLayout->addStretch();

    mainLayout->addLayout(buttonsLayout);
    setLayout(mainLayout);

    setFixedSize(500, 200);
}

bool CommentEditDialog::eventFilter( QObject * object, QEvent * event )
{
    if (object == m_edit && event->type() == QEvent::KeyPress) {
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
        if (keyEvent->key() == Qt::Key_Return && QApplication::keyboardModifiers() & Qt::ControlModifier) {
            accept();
        } else
            return false;
    }
    return false;
}

void CommentEditDialog::setText( const QString & text )
{
    m_edit->setText(text);
}

QString CommentEditDialog::text()
{
    return m_edit->document()->toPlainText();
}

///////// Class 'LeftMarginWidget' implementation //////////////////////////////////////////////////

LeftMarginWidget::LeftMarginWidget( QWidget * parent )
    : QWidget(parent)
{
    setFixedWidth(marginWidth);
}

void LeftMarginWidget::paintEvent( QPaintEvent * event )
{
    QPainter painter(this);
    painter.fillRect(rect(), QColor(235, 235, 255));
    painter.setPen(QColor(180, 200, 140));
    foreach(int yPos, m_bookmarksList)
    {
        QRect bookmarkRect(2, yPos, 15, 15);
        painter.fillRect(bookmarkRect, QColor(200, 220, 160));
        painter.drawRect(bookmarkRect);
    }
}

void LeftMarginWidget::setBookMarksList( const QList<int> & list )
{
    m_bookmarksList = list;
    repaint();
}

void LeftMarginWidget::mousePressEvent( QMouseEvent * event )
{
    emit clicked(event->pos().y());
}

///////// Class 'ItemsListMarginWidget' implementation /////////////////////////////////////////////

ItemsListMarginWidget::ItemsListMarginWidget( QWidget * parent )
    : QWidget(parent)
{
    m_showPointer = true;

    setFixedWidth(widgetWidth);
}

void ItemsListMarginWidget::setPointerPos( int top, int bottom )
{
    m_topPointerPos = top;
    m_bottomPointerPos = bottom;
    repaint();
}

bool ItemsListMarginWidget::pointerIsVisible() const
{
    return m_showPointer;
}

void ItemsListMarginWidget::setPointerVisible( bool visible )
{
    if(m_showPointer == visible)
        return;

    m_showPointer = visible;
    repaint();
}

void ItemsListMarginWidget::paintEvent( QPaintEvent * event )
{
    QPainter painter(this);
    painter.fillRect(rect(), Qt::white);
    if(!m_showPointer)
        return;

    if(m_bottomPointerPos == -1)
    {
        QPolygon triangle;
        triangle.append(QPoint(widgetWidth - 6, m_topPointerPos - 5));
        triangle.append(QPoint(widgetWidth - 1, m_topPointerPos));
        triangle.append(QPoint(widgetWidth - 6, m_topPointerPos + 5));
        QPainterPath trianglePath;
        trianglePath.addPolygon(triangle);
        painter.setRenderHint(QPainter::Antialiasing);
        painter.fillPath(trianglePath, QColor(100, 100, 255));
    }
    else
    {
        painter.setPen(QPen(QColor(100, 100, 255), 2));
        painter.drawLine(widgetWidth - 4, m_topPointerPos,
                         widgetWidth - 4, m_bottomPointerPos);
    }
}

///////// Class 'ItemsListWidget' implementation ///////////////////////////////////////////////////

ItemsListWidget::ItemsListWidget( QWidget * parent )
    : QTreeWidget(parent)
{
    setRootIsDecorated(false);
    setHeaderHidden(true);
    setMouseTracking(true);

    m_highlightedItem = 0;

//    m_marginWidget = new ItemsListMarginWidget(this);
//    m_marginWidget->setFixedHeight(2000);
//    m_marginWidget->setPointerVisible(false);
//    m_marginWidget->move(0, 0);
//    m_marginWidget->hide();

    ItemsListDelegate * delegate = new ItemsListDelegate(this);
    setItemDelegate(delegate);
    header()->setOffset(-10);

    connect(this, SIGNAL(itemClicked(QTreeWidgetItem *, int)),
            this, SLOT(itemIsClicked(QTreeWidgetItem*)));
    connect(this, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)),
            this, SLOT(itemIsDoubleClicked(QTreeWidgetItem*)));
}

void ItemsListWidget::setItemsList( const QModelIndexList & indexList )
{
    while(topLevelItemCount())
        takeTopLevelItem(0);

    m_highlightedItem = 0;
    if(indexList.isEmpty())
    {
//        m_marginWidget->setPointerVisible(false);
        return;
    }

//    m_marginWidget->setPointerVisible(true);
    QModelIndexList tmpIndexList = indexList;
//    qSort(tmpIndexList.begin(), tmpIndexList.end(), DynamicModel::indexLessThen);
    foreach(QModelIndex index, tmpIndexList)
    {
        QTreeWidgetItem * item = new QTreeWidgetItem();
        item->setData(0, RoleIndex, QVariant::fromValue(index));
        addTopLevelItem(item);
    }
}

void ItemsListWidget::addItem( const QModelIndex & index )
{
//    if(!m_marginWidget->pointerIsVisible())
//        m_marginWidget->setPointerVisible(true);

    QTreeWidgetItem * item = new QTreeWidgetItem();
    item->setData(0, RoleIndex, QVariant::fromValue(index));
    insertTopLevelItem(findPlaceForItem(index), item);
    setScreenPos(m_topScreenPointIndex, m_bottomScreenPointIndex);
}

void ItemsListWidget::removeItem( const QModelIndex & index )
{
    takeTopLevelItem(findItem(index));

//    if(topLevelItemCount() == 0)
//        m_marginWidget->setPointerVisible(false);

    setScreenPos(m_topScreenPointIndex, m_bottomScreenPointIndex);
}

void ItemsListWidget::setScreenPos( const QModelIndex & top, const QModelIndex & bottom )
{
    int topPos;
    int bottomPos;
    int topIndex;
    int bottomIndex;

    m_topScreenPointIndex = top;
    m_bottomScreenPointIndex = bottom;

    if(m_topScreenPointIndex.isValid())
        topIndex = findPlaceForItem(top);
    else
        topIndex = 0;

    if(m_bottomScreenPointIndex.isValid())
        bottomIndex = findPlaceForItem(bottom);
    else
        bottomIndex = topLevelItemCount() - 1;

    if(topIndex < topLevelItemCount())
        topPos = visualItemRect(topLevelItem(topIndex)).top();
    else
        topPos = visualItemRect(topLevelItem(topIndex - 1)).bottom();

    if(topIndex == bottomIndex)
        bottomPos = -1;
    else
    {
        if(bottomIndex == 0)
            bottomPos = visualItemRect(topLevelItem(0)).top();
        else
            bottomPos = visualItemRect(topLevelItem(bottomIndex - 1)).bottom();
    }

//    m_marginWidget->setPointerPos(topPos, bottomPos);
}

void ItemsListWidget::mouseMoveEvent( QMouseEvent *event )
{
    QTreeWidgetItem * item = itemAt(event->pos());

    if(item)
    {
        QModelIndex itemIndex = item->data(0, RoleIndex).value<QModelIndex>();
        QRect itemRect(visualItemRect(item).topLeft(), TreeViewDelegate::itemVisualSize(itemIndex));

        if(!itemRect.contains(event->pos()))
            item = 0;
    }

    if(item)
    {
        QModelIndex itemIndex = item->data(0, RoleIndex).value<QModelIndex>();
        TreeViewDelegate::itemVisualSize(itemIndex);
        setCursor(Qt::PointingHandCursor);
        setHighlighted(item);
    }
    else
    {
        setCursor(Qt::ArrowCursor);
        setHighlighted(0);
    }

    repaint();
}

void ItemsListWidget::leaveEvent( QEvent * event )
{
    setHighlighted(0);
}

void ItemsListWidget::scrollContentsBy( int dx, int dy )
{
    QTreeWidget::scrollContentsBy(dx, dy);
//    m_marginWidget->move(0, 0);
}

void ItemsListWidget::itemIsClicked( QTreeWidgetItem * item )
{
    emit itemClicked(item->data(0, Qt::UserRole).value<QModelIndex>(), false);
}

void ItemsListWidget::itemIsDoubleClicked( QTreeWidgetItem * item )
{
    emit itemClicked(item->data(0, Qt::UserRole).value<QModelIndex>(), true);
}

void ItemsListWidget::setHighlighted( QTreeWidgetItem * item )
{
    if(m_highlightedItem == item)
        return;

    if(m_highlightedItem)
    {
        QRect highlightRect = visualItemRect(m_highlightedItem);
        m_highlightedItem->setData(0, RoleHighlight, false);
        m_highlightedItem = 0;
        repaint(highlightRect);
    }

    m_highlightedItem = item;

    if(item)
    {
        m_highlightedItem->setData(0, RoleHighlight, true);
        repaint(visualItemRect(m_highlightedItem));
    }
}

int ItemsListWidget::findPlaceForItem( const QModelIndex & index )
{
//    for(int i = 0; i < topLevelItemCount(); i++)
//    {
//        QTreeWidgetItem * item = topLevelItem(i);
//        QModelIndex itemIndex = item->data(0, RoleIndex).value<QModelIndex>();
//        if(DynamicModel::indexLessThen(index, itemIndex))
//            return i;
//    }

    return topLevelItemCount();
}

int ItemsListWidget::findItem( const QModelIndex & index )
{
    for(int i = 0; i < topLevelItemCount(); i++)
    {
        QTreeWidgetItem * item = topLevelItem(i);
        QModelIndex itemIndex = item->data(0, RoleIndex).value<QModelIndex>();
        if(itemIndex == index)
            return i;
    }

    return -1;
}

///////// Class 'ItemsListDelegate' implementation /////////////////////////////////////////////////

ItemsListDelegate::ItemsListDelegate( QObject * parent )
    : QItemDelegate(parent)
{

}

void ItemsListDelegate::paint( QPainter * painter,
                               const QStyleOptionViewItem & option,
                               const QModelIndex & index ) const
{
    QModelIndex itemIndex = index.data(ItemsListWidget::RoleIndex).value<QModelIndex>();
    if(!itemIndex.isValid())
        return;

    TreeViewDelegate::drawItem(itemIndex, painter, option.rect);
    bool isHighlited = index.data(ItemsListWidget::RoleHighlight).toBool();
    if(isHighlited)
    {
        QRect itemRect = option.rect;
        itemRect.setSize(TreeViewDelegate::itemVisualSize(itemIndex));
        QPainterPath painterPath;
        painterPath.addRoundedRect(itemRect, 3, 3);
        painter->setRenderHint(QPainter::Antialiasing);
        painter->fillPath(painterPath, QColor(230, 230, 255));
        painter->setRenderHint(QPainter::Antialiasing, false);
    }

    TreeViewDelegate::drawItem(itemIndex, painter, option.rect);
}

QSize ItemsListDelegate::sizeHint( const QStyleOptionViewItem & option, const QModelIndex & index) const
{
    ARSExecItem * item = index.data(TreeViewModel::RoleItemData).value<ARSExecItem *>();
    QSize size;

    QFontMetrics defaultFontMetrics(g_Settings.itemStyle("ARSExecItem")->font());
    size = QSize(option.rect.width(), defaultFontMetrics.height());

    return size;
}

////////// TreeViewSearchModel /////////////////////////////////////////////////////////////////////

TreeViewSearchModel::TreeViewSearchModel(const ARSDummyObjectList & list, QObject * parent)
    : QAbstractListModel(parent)
{
    m_list = list;

    m_iconMap.insert(ARSObject::Form, QIcon(":/objects/form"));
    m_iconMap.insert(ARSObject::Field, QIcon(":/objects/field"));
    m_iconMap.insert(ARSObject::Guide, QIcon(":/objects/guide"));
    m_iconMap.insert(ARSObject::ActiveLink, QIcon(":/objects/active_link"));
    m_iconMap.insert(ARSObject::Filter, QIcon(":/objects/filter"));
}

int TreeViewSearchModel::rowCount(const QModelIndex &parent) const
{
    int listCount = m_list.count();
    return m_list.count();
}

QVariant TreeViewSearchModel::data(const QModelIndex &index, int role) const
{
    if(!index.isValid())
        return QVariant();

    if(role == Qt::DisplayRole || role == Qt::EditRole)
        return m_list.at(index.row())->name(true);

    if(role == Qt::UserRole)
        return QVariant::fromValue(m_list.at(index.row()));

    if(role == Qt::DecorationRole)
        return m_iconMap.value(m_list.at(index.row())->type());

    return QVariant();
}

////////// TreeViewSearchWidget ////////////////////////////////////////////////////////////////////

TreeViewSearchWidget::TreeViewSearchWidget(QWidget *parent)
    : QWidget(parent)
{
    QHBoxLayout * layout = new QHBoxLayout(this);
    layout->setContentsMargins(0, 0, 0, 0);
    layout->setSpacing(0);

    m_comboBox = new QComboBox(this);
    m_comboBox->setEditable(true);
    m_comboBox->setMaxVisibleItems(50);
    m_comboBox->setIconSize(QSize(16, 16));
    layout->addWidget(m_comboBox);

    m_SearchButton = new QToolButton(this);
    QIcon searchIcon;
    searchIcon.addPixmap(QPixmap(":/qss/searchwidget_icon"), QIcon::Normal);
    searchIcon.addPixmap(QPixmap(":/qss/searchwidget_disabled_icon"), QIcon::Disabled);
    m_SearchButton->setIcon(searchIcon);
    connect(m_SearchButton, SIGNAL(clicked()), this, SLOT(searchButtonClicked()));
    connect(m_comboBox->lineEdit(), SIGNAL(returnPressed()), this, SLOT(searchButtonClicked()));
    connect(m_comboBox->lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(textChanged()));
    connect(m_comboBox, SIGNAL(activated(int)), this, SLOT(itemSelected(int)));
    layout->addWidget(m_SearchButton);

    setLayout(layout);
}

void TreeViewSearchWidget::setModel(TreeViewSearchModel * model)
{
    m_comboBox->setModel(model);
    QCompleter * completer = m_comboBox->completer();
    completer->setModel(model);
    completer->setCompletionRole(Qt::DisplayRole);
    completer->setCompletionMode(QCompleter::PopupCompletion);
    m_comboBox->setCompleter(completer);
}

void TreeViewSearchWidget::searchButtonClicked()
{
    ARSDummyObject * object = currentObject();

    if(object)
        emit searchObject(object);
//    else
//        emit searchText(m_comboBox->currentText());
}

void TreeViewSearchWidget::textChanged()
{
    m_SearchButton->setEnabled(false);
    if(m_comboBox->currentIndex() != -1)
    {
        QString text = m_comboBox->currentText();
        m_comboBox->setCurrentIndex(-1);
        m_comboBox->setEditText(text);
    }
}

void TreeViewSearchWidget::itemSelected(int index)
{
    if(index >= 0)
        m_SearchButton->setEnabled(true);
}

ARSDummyObject * TreeViewSearchWidget::currentObject() const
{
    QVariant data = m_comboBox->itemData(m_comboBox->currentIndex());

    if(data.isNull())
        return 0;

    return data.value<ARSDummyObject *>();
}

////////// TreeViewPlugin //////////////////////////////////////////////////////////////////////////

TreeViewPlugin::TreeViewPlugin(QObject * parent)
    : QObject(parent)
{
}

QString TreeViewPlugin::name()const
{
    return "treeview";
}

QString TreeViewPlugin::description()const
{
    return tr("This plugin provides tree representation of ARS log files");
}

bool TreeViewPlugin::loadSettings()
{
    return g_Settings.readSettings();
}

QString TreeViewPlugin::viewName()const
{
    return tr("Tree");
}

ViewWidget::ViewType TreeViewPlugin::viewType() const
{
    return ViewWidget::DynamicModelView;
}

QIcon TreeViewPlugin::icon(bool active)const
{
    return QIcon(":/view/treeview_icon");
}

DynamicViewWidget * TreeViewPlugin::createView(QWidget * parent)const
{
    return new TreeViewWidget(parent);
}

ToolBarItemList TreeViewPlugin::toolBarItems(QObject * parent)const
{
    ToolBarItemList list;
    ToolBarItem * toolBarItem;

    QAction * action = new QAction(QIcon(":/icons/copy_item"), tr("Copy Selected Item"), parent);
    action->setShortcut(QKeySequence("Ctrl+C"));
    toolBarItem = new ToolBarAction(action, "copyItem", parent);
    toolBarItem->setObjectName("copyItem");
    list.append(toolBarItem);

    QActionGroup * filterGroup = new QActionGroup(parent);

    action = new QAction(QIcon(":/icons/show_all"), tr("Show All Workflow"), parent);
    action->setCheckable(true);
    filterGroup->addAction(action);
    toolBarItem = new ToolBarAction(action, QString(), parent);
    toolBarItem->setObjectName("showAllWorkflow");
    list.append(toolBarItem);

    action = new QAction(QIcon(":/icons/hide_empty"), tr("Hide Empty Workflow"), parent);
    action->setCheckable(true);
    filterGroup->addAction(action);
    toolBarItem = new ToolBarAction(action, QString(), parent);
    toolBarItem->setObjectName("hideEmptyWorkflow");
    list.append(toolBarItem);

    action = new QAction(QIcon(":/icons/hide_internal"), tr("Hide Internal Workflow"), parent);
    action->setCheckable(true);
    filterGroup->addAction(action);
    toolBarItem = new ToolBarAction(action, QString(), parent);
    toolBarItem->setObjectName("hideInternalWorkflow");
    list.append(toolBarItem);

    action = new QAction(QIcon(":/icons/bookmarks"), tr("Show/Hide Bookmarks"), parent);
    action->setCheckable(true);
    toolBarItem = new ToolBarAction(action, QString(), parent);
    toolBarItem->setObjectName("showBookmarks");
    list.append(toolBarItem);

    TreeViewSearchWidget * searchWidget = new TreeViewSearchWidget();
    QFile file(":/qss/searchwidget");
    file.open(QFile::ReadOnly);
    searchWidget->setStyleSheet(file.readAll());
    toolBarItem = new ToolBarWidget(searchWidget, parent);
    toolBarItem->setObjectName("search");
    list.append(toolBarItem);

    return list;
}

SettingsWidget * TreeViewPlugin::settingsWidget(QWidget * parent)const
{
    return 0;
}

void TreeViewPlugin::appEvent(AppEvent * event)
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////

Q_EXPORT_PLUGIN2(treeview, TreeViewPlugin)

////////////////////////////////////////////////////////////////////////////////////////////////////
